package cn.apotato.inclusion.commin.response;

import cn.apotato.inclusion.commin.enums.InclusionStrategy;

import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author xphu
 * @version 1.0
 * @date 2021/8/6 12:01
 */
public class ResponseMessage extends Message {

    /**
     * 默认的成员key
     */
    public final String CODE_KEY = "code";
    public final String MESSAGE_KEY = "message";
    public String DATA_KEY = "data";
    public String LIST_KEY = "list";
    public String ARRAY_KEY = "arrays";
    public String SUCCESS_KEY = "success";
    public final static String TIME_STAMP = "timestamp";
    public final static String DATE_TIME = "dateTime";


    private InclusionStrategy tiled = InclusionStrategy.WITH_KEY;
    private Object data;
    private final Message response;

    {
        response = new Message();
    }

    /*** 创建对象构造器
     * @return ResponseMessage
     */
    public static ResponseMessage builder(){
        return new ResponseMessage();
    }

    public ResponseMessage success(){
        response.put(CODE_KEY ,ResponseCode.SUCCESS.code);
        response.put(MESSAGE_KEY ,ResponseCode.SUCCESS.message);
        return this;
    }

    public ResponseMessage fail(){
        fail(ResponseCode.FAIL.code, ResponseCode.FAIL.message);
        return this;
    }

    public ResponseMessage fail(String msg){
        fail(ResponseCode.FAIL.code, msg);
        return this;
    }

    public ResponseMessage fail(int code,String msg){
        response.put(CODE_KEY ,code);
        response.put(MESSAGE_KEY ,msg);
        response.put(SUCCESS_KEY, false);
        return this;
    }


    public ResponseMessage fail(String key,Object data){
        fail(ResponseCode.FAIL.code, ResponseCode.FAIL.message);
        this.data = data;
        this.DATA_KEY = key;
        return this;
    }

    public ResponseMessage success(Object data){
        success(DATA_KEY, data);
        return this;
    }

    public ResponseMessage success(String key,Object data){
        response.put(CODE_KEY ,ResponseCode.SUCCESS.code);
        response.put(MESSAGE_KEY ,ResponseCode.SUCCESS.message);
        this.data = data;
        this.DATA_KEY = key;
        return this;
    }

    public ResponseMessage timeStamp(){
        response.put(TIME_STAMP , LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli());
        return this;
    }

    public ResponseMessage dateTime(){
        response.put(DATE_TIME , LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        return this;
    }

    /**
     *
     * @param pattern yyyy-MM-dd HH:mm:ss
     */
    public ResponseMessage dateTime(String pattern){
        response.put(DATE_TIME , LocalDateTime.now().format(DateTimeFormatter.ofPattern(pattern)));
        return this;
    }

    public ResponseMessage tiled(InclusionStrategy tiled){
        this.tiled = tiled;
        return this;
    }

    public Message build() {
        try {
            this.tiled();
        } catch (Exception e){
            e.printStackTrace();
        }
        return response;
    }

    public void tiled() throws IllegalAccessException {
        if (data == null){
            return;
        }
        if (data instanceof Object[]){
            response.put(ARRAY_KEY, data);
            response.put("size", ((Object[]) data).length);
            return;
        }
        if (data instanceof Collection){
            response.put(LIST_KEY, data);
            response.put("size", ((Collection<?>) data).size());
            return;
        }
        if (tiled == InclusionStrategy.TILED){
            if (data instanceof Map){
                Map map = (Map)this.data;
                for (Object key : map.keySet()) {
                    response.put((String) key, map.get(key));
                }
            } else{
                Class<?> aClass = data.getClass();
                for (Field field : aClass.getDeclaredFields()) {
                    field.setAccessible(true);
                    response.put(field.getName(), field.get(data));
                    field.setAccessible(false);
                }
            }
        } else {
            response.put(DATA_KEY, data);
        }
    }

}